import pickle
import base64
from django.shortcuts import render
from django_redis import get_redis_connection
from rest_framework import response
from rest_framework import status
from rest_framework.generics import CreateAPIView,GenericAPIView
# Create your views here.
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from carts.serializers import CartsSerializers, CartsdelSerializers, CartsSelectSerializers
from goods.models import SKU
from goods.serializers import SkuSerializer
from user.models import User


class CartsView(GenericAPIView):
    # get的序列化器要包含所有的sku字段，并且需要count,selected序列化返回
    # post和put只需要sku_id,count,selected三个值，且必须输入
    serializer_class = CartsSerializers

    def perform_authentication(self, request):
        pass

    def post(self,request):
        try:
            user = request.user
        except:
            user = None
        # 记住自己用的序列化器有没自己想要的字段
        ser = self.get_serializer(data=request.data)
        # 验证的时候从selected字段中添加默认值
        ser.is_valid(raise_exception=True)
        sku_id = ser.validated_data['sku_id']
        count = ser.validated_data['count']
        selected = ser.validated_data['selected']

        if user:
            conn = get_redis_connection('cart')
            pl = conn.pipeline()
            # hincrby用法:每次传来相同的sku_id值，
            # 如果存在sku_id这个字段，会在原来的字段上的count加上新的count
            pl.hincrby('carts_%s'%user.id,sku_id,count)
            if selected:
                pl.sadd('carts_selected_%s'%user.id,sku_id)
            pl.execute()
            return Response(ser.data,status=status.HTTP_201_CREATED)

        else:
            # 用户未登录，在cookie中保存
            # {
            #     sku_id: { "count": 10, "selected": true},
            #     ...
            # }
            cart = request.COOKIES.get('cart_cookie')
            if cart:
                # 先cart.encode()变成字节码，
                # 再用base64把随机加密过的字符串解密成十六进制，
                # 再交给pickle解密十六进制的字节码
                cart = pickle.loads(base64.b64decode(cart.encode()))
            else:
                cart = {}

            sku = cart.get(sku_id)
            if sku:
                # 把前端传来的count加上cookie的count
                count = int(sku['count'])+count
            # 如果cart字典有值，并且sku_id存在就覆盖原本sku_id的值，如果sku_id不存在就新增sku_id这个字段
            # 如果cart不存在，就新增sku_id这个字段
            cart[sku_id] = {
                'count':count,
                'selected':selected
            }
            # 先用pickle把字典变成十六进制字节码，
            # 再用base64加密成随机的字符串，
            # 再把字节码变成字符串
            cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()

            response = Response(ser.data,status=status.HTTP_201_CREATED)

            response.set_cookie('cart_cookie',cart_cookie,60*60*24*7)

            return response

    def get(self,request):

        try:
            user = request.user
        except:
            user = None

        # 1.先从redis中获取包含所有sku_id和count键值对的字典，selected值
        # 2.再遍历cart.items()方法，取出每个sku_id和count值
        # 3.遍历时sku_id作为字典名,把count和selected放到该sku_id字典中，以此类推,组建每个sku_id字典,再把每个sku_id字典放到cart空字典中
        # 4.判断SKU表中id在cart字典sku_id键中的所有sku查询集
        # 5.遍历该查询集并在每个sku对象加上count和selected属性
        # 6.序列化返回该查询集skus
        if user:
            conn = get_redis_connection('cart')
            # pl = conn.pipeline()
            # 返回一个包含所有键值对的字典 {b'11': b'2', b'16': b'1'}
            cart_dict= conn.hgetall('carts_%s' % user.id)
            print(cart_dict)
            # 返回一个列表
            selected = conn.smembers('carts_selected_%s' % user.id)
            # pl.execute()
            # print(selected)
            cart = {}
            print(cart_dict.items())
            # cart_dict.items()是([(b'11', b'2'), (b'16', b'1')])
            for sku_id,count in cart_dict.items():
                sku = SKU.objects.get(id=sku_id)
                cart[int(sku_id)] = {
                    'count':count,
                    'selected':sku_id in selected
                }

        else:
            # 用户未登录，在cookie中保存
            # {
            #     sku_id: { "count": 10, "selected": true},
            #     ...
            # }
            cart = request.COOKIES.get('cart_cookie')
            if cart:
                # 先cart.encode()变成字节码，
                # 再用base64把随机加密过的字符串解密成十六进制，
                # 再交给pickle解密十六进制的字节码
                cart = pickle.loads(base64.b64decode(cart.encode()))
            else:
                cart = {}
            # 取出所有sku_id的sku对象的查询集
        skus = SKU.objects.filter(id__in=cart.keys())

        for sku in skus:
            sku.count = cart[sku.id]['count']
            sku.selected = cart[sku.id]['selected']

        ser = self.get_serializer(skus, many=True)
        # print(skus[0].selected,skus[1].selected)
        # print(ser.data)
        return Response(ser.data,status=status.HTTP_200_OK)

    # 修改接口每点击一次选中或者数量都会发送请求，
    # 所以实际上每次只是传来２个参数sku_id,count或者sku_id,selected
    def put(self,request):

        # 1.反序列化接受验证参数，获取３个参数
        # 2.如果用户未登录就通过user_id修改sku_id字段的count值
        # 3.判断selected是选中还是未选中,如果选中把传来的sku_id放进集合中
        # 4.如果selected是未选中，删掉集合中含有该sku_id的值,序列化返回ser.data
        # 5.如果用户未登录,获取cookie中的cart值
        # 6.判断是cart是否有值，如果有值就解密cart值，没有就报错
        # 7.修改解密后的cart值中sku_di中的count值和selected值
        # 8.加密cart值和反序列化并把cart值设置成cookie
        # 9.返回响应对象

        try:
            user = request.user
        except:
            user = None
        ser = self.get_serializer(data=request.data)
        # 返回值为布尔值
        ser.is_valid(raise_exception=True)
        sku_id = ser.validated_data['sku_id']
        count = ser.validated_data['count']
        # 传来的是布尔值
        selected = ser.validated_data['selected']

        if user:
            conn = get_redis_connection('cart')
            pl = conn.pipeline()
            print(11)
            pl.hset('carts_%s'%user.id,sku_id,count)
            # 如果为选中状态就把sku_id存在集合中
            if selected:
                pl.sadd('carts_selected_%s'%user.id,sku_id)
            # 反之则在该集合中删除sku_id
            else:
                pl.srem('carts_selected_%s'%user.id,sku_id)
            pl.execute()
            print(ser.data)
            return Response(ser.data,status=status.HTTP_201_CREATED)

        else:
            cart = request.COOKIES.get('cart_cookie')
            if cart:
                cart = pickle.loads(base64.b64decode(cart.encode()))
            else:
                return Response({'message':'没有该cookie或已过期'},status=status.HTTP_400_BAD_REQUEST)

            sku = cart.get(sku_id)
            if sku:
                sku['count'] = count
                sku['selected'] = selected
            else:
                return Response({"message":'错误的cookie值'})

            cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()

            response = Response(ser.data,status=status.HTTP_201_CREATED)

            response.set_cookie("cart_cookie",cart_cookie,60*60*24*7)

            return response

    def delete(self,request):

        try:
            user = request.user
        except:
            user = None
        ser = CartsdelSerializers(data=request.data)
        ser.is_valid(raise_exception=True)
        sku_id = ser.validated_data['sku_id']

        if user:
            conn = get_redis_connection('cart')
            pl = conn.pipeline()
            pl.hdel('carts_%s' % user.id, sku_id)
            pl.srem('carts_selected_%s' % user.id, sku_id)

            pl.execute()

            return Response({'message':'ok'},status=status.HTTP_201_CREATED)

        # 删除cart值中的键值对，返回空字典
        else:
            cart = request.COOKIES.get('cart_cookie')
            if cart:
                cart = pickle.loads(base64.b64decode(cart.encode()))
            else:
                return Response({'message': '没有该cookie或已过期'}, status=status.HTTP_400_BAD_REQUEST)

            sku = cart.get(sku_id)
            if sku:
                # 删除该sku_id，其他的sku_id还存在
                cart.pop(sku_id)
            else:
                return Response({"message": '错误的cookie值'})

            cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()

            response = Response(ser.data, status=status.HTTP_201_CREATED)

            response.set_cookie("cart_cookie", cart_cookie, 60 * 60 * 24 * 7)

            return response


# 全选
class CartsSelectView(GenericAPIView):
    serializer_class = CartsSelectSerializers

    def perform_authentication(self, request):
        pass


    def put(self,request):
        try:
            user = request.user
        except Exception:
            user = None

        serializer = CartsSelectSerializers(data=request.data)
        serializer.is_valid(raise_exception=True)
        selected = serializer.validated_data['selected']

        if user:
            conn = get_redis_connection('cart')
            # pl = conn.pipeline()
            # 存在哈西中的商品，不管是选中还是未选中都有
            cart_dict = conn.hgetall('carts_%s' % user.id)
            cart_list = cart_dict.keys()
            if selected:
                conn.sadd('carts_selected_%s' % user.id,*cart_list)
            else:
                conn.srem('carts_selected_%s' % user.id,*cart_list)
            # pl.execute()

            return Response({'message':'ok'},status=status.HTTP_204_NO_CONTENT)

        else:
            cart = request.COOKIES.get('cart_cookie')
            response = Response({'message':'ok'},status=status.HTTP_204_NO_CONTENT)
            if cart:
                cart = pickle.loads(base64.b64decode(cart.encode()))

                for sku_id in cart:
                    print(sku_id)
                    cart[sku_id]['selected'] = selected

                cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()

                response.set_cookie("cart_cookie",cart_cookie,60*60*24*7)
            return response